﻿using EBA.IoC;
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Linq;

namespace EBA.Framework
{
    /// <summary>
    /// 插件运行时。负责插件的安装，启动，停止，卸载和更新。
    /// </summary>
    [Serializable]
    public class BundleRuntime<TBundle> : MarshalByRefObject, IDisposable where TBundle : IBundle
    {

        IContainer _Container;

        /// <summary>
        /// Default container instance
        /// </summary>
        protected virtual IContainer Container
        {
            get
            {
                if (_Container == null)
                {
                    //  Debugger.Launch();
                    var config = new ContainerConfiguration();

                    config.WithAssemblies(WindowsAssembly.GetAssemblies());

                    _Container = config.CreateContainer();
                }

                return _Container;
            }
        }

        public BundleRuntime()
            : this(null)
        {
        }


        /// <summary>
        /// 构造函数
        /// </summary>
        public BundleRuntime(string configPath = null)
        {
            this.Configuration = new FrameworkConfiguration(configPath);
        }

        /// <summary>
        /// 框架配置信息
        /// </summary>
        public FrameworkConfiguration Configuration { get; private set; }


        #region Bundles
        List<IBundleContext> _BundleContextes = new List<IBundleContext>();

        /// <summary>
        /// 上下文列表
        /// </summary>
        public virtual IEnumerable<IBundleContext> BundleContextes
        {
            get
            {
                return this._BundleContextes;
            }
        }

        string _Id;
        /// <summary>
        /// 标识
        /// </summary>
        public virtual string Id
        {
            get
            {
                if (this._Id == null)
                {
                    this._Id = Guid.NewGuid().ToString("N");
                }
                return this._Id;
            }
        }

        /// <summary>
        /// 为指定的插件创建相应的上下文实例
        /// </summary>
        /// <param name="bundleId"></param>
        /// <returns></returns>
        protected virtual IBundleContext CreateBundleContext(string bundleId)
        {
            Debugger.Launch();
            var bundleConfig = this.Configuration.Framework.Bundles
                .AsEnumerable
                .Where(i => i.Id == bundleId)
                .FirstOrDefault();

            if (bundleConfig == null)
            {
                throw new BundleConfigurationElementNotFoundException(bundleId);
            }

            var contextName = bundleConfig.Context;

            if (string.IsNullOrWhiteSpace(contextName))
            {
                throw new MissingBundleContextNameException(bundleId);
            }

            IBundleContext context;

            if (Container.TryGetExport<IBundleContext>(contextName, out context))
            {
                return context;
            }
            else
            {
                throw new InvalidBundleContextNameException(bundleId, contextName);
            }

        }

        /// <summary>
        /// 获取指定插件的启动路径
        /// </summary>
        /// <param name="bundleId"></param>
        /// <returns></returns>
        protected virtual string GetBundleStartupPath(string bundleId)
        {
            return Path.Combine(AppRuntime.ApplicationPath, this.Configuration.Framework.Plugins, bundleId);
        }

        /// <summary>
        /// 插件启动前
        /// </summary>
        /// <param name="context"></param>
        protected virtual void OnBundleStarting(IBundleContext context)
        {
            if (this.BundleStarting != null)
            {
                this.BundleStarting(this, context);
            }
        }

        /// <summary>
        /// 插件启动后
        /// </summary>
        /// <param name="contex"></param>
        protected virtual void OnBundleStarted(IBundleContext context)
        {
            if (this.BundleStartted != null)
            {
                this.BundleStartted(this, context);
            }
        }

        /// <summary>
        /// 插件停止前
        /// </summary>
        /// <param name="context"></param>
        protected virtual void OnBundleStoping(IBundleContext context)
        {
            if (this.BundleStopping != null)
            {
                this.BundleStopping(this, context);
            }
        }

        /// <summary>
        /// 插件停止后
        /// </summary>
        /// <param name="contex"></param>
        protected virtual void OnBundleStopped(IBundleContext context)
        {
            if (this.BundleStopped != null)
            {
                this.BundleStopped(this, context);
            }
        }

        /// <summary>
        /// 插件异常后
        /// </summary>
        /// <param name="contex"></param>
        protected virtual void OnBundleUnhandledException(string bundelId, Exception innerException)
        {
            if (this.BundleUnhandledException != null)
            {
                this.BundleUnhandledException(bundelId, innerException);
            }
        }

        /// <summary>
        /// 启动插件
        /// </summary>
        /// <param name="bundleId"></param>
        public virtual IBundleContext Start(string bundleId)
        {
            try
            {
                var context = GetBundleContext(bundleId);
                if (context == null)
                {
                    context = CreateBundleContext(bundleId);
                    context.Initialize<TBundle>(this.Id, this.GetBundleStartupPath(bundleId), bundleId);
                    this._BundleContextes.Add(context);
                }
                this.OnBundleStarting(context);
                var bundleName = context.Bundle.Name;

                context.Bundle.Start();

                this.OnBundleStarted(context);

                return context;
            }
            catch (Exception ex)
            {
                this.OnBundleUnhandledException(bundleId, ex);
                return null;
            }
        }

        /// <summary>
        /// 获取指定插件的上下文。如果还没注册，则返回空。
        /// </summary>
        /// <param name="bundleId"></param>
        /// <returns></returns>
        protected IBundleContext GetBundleContext(string bundleId)
        {
            return this.BundleContextes.Where(i => i.Bundle.Id == bundleId).FirstOrDefault();
        }

        /// <summary>
        /// 停止插件
        /// </summary>
        /// <param name="bundleId"></param>
        public virtual void Stop(string bundleId)
        {
            try
            {
                var context = GetBundleContext(bundleId);

                if (context != null)
                {
                    this.OnBundleStoping(context);
                    context.Bundle.Stop();
                    this.OnBundleStopped(context);
                }
            }
            catch (Exception ex)
            {
                this.OnBundleUnhandledException(bundleId, ex);
            }
        }

        #endregion

        #region Dispose
        /// <summary>
        /// 是否已被手工释放
        /// </summary>
        bool _Disposed = false;
        /// <summary>
        /// 析构函数，释放资源。
        /// </summary>
        ~BundleRuntime()
        {
            Dispose(false);
        }

        /// <summary>
        /// 释放资源
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        /// <summary>
        /// 手动释放资源
        /// </summary>
        /// <param name="disposing"></param>
        protected virtual void Dispose(bool disposing)
        {
            if (!_Disposed)
            {
                if (disposing)
                {
                    FreeManagedResources();

                    GC.SuppressFinalize(this);
                }
                _Disposed = true;
            }
        }

        /// <summary>
        /// 释放托管资源
        /// </summary>
        protected virtual void FreeManagedResources()
        {
            foreach (var context in this.BundleContextes)
            {
                context.Dispose();
            }

            this._BundleContextes.Clear();
            this._BundleContextes = null;
        }


        public override object InitializeLifetimeService()
        {
            return null;
        }
        #endregion

        /// <summary>
        /// 插件启动前
        /// </summary>
        public event BundleEvenHandler BundleStarting;
        /// <summary>
        /// 插件启动后
        /// </summary>
        public event BundleEvenHandler BundleStartted;
        /// <summary>
        /// 插件停止前
        /// </summary>
        public event BundleEvenHandler BundleStopping;
        /// <summary>
        /// 插件停止后
        /// </summary>
        public event BundleEvenHandler BundleStopped;
        /// <summary>
        /// 插件发生异常后
        /// </summary>
        public event BundleUnhandledExceptionEventHanlder BundleUnhandledException;



    }

    public delegate void BundleEvenHandler(object sender, IBundleContext context);
    public delegate void BundleUnhandledExceptionEventHanlder(string bundleId, Exception innerException);

}
